package snapex.expense.controller;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import snapex.core.model.Expense;
import snapex.core.model.InvoiceImage;
import snapex.core.model.Result;
import snapex.expense.service.IExpenseService;
import snapex.invoice.service.IInvoiceService;

@Slf4j
@RestController
public class UploadController {

	@Autowired
	IExpenseService expenseService;
	
	@Autowired
	IInvoiceService invoiceService;
	
	@Value("${snapex.supportedUploadFileTypes}")
	String supportedUploadFileTypes;
	
	@ApiOperation(value="Upload expense")
	@PostMapping(value = "/expense/upload", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Result> uploadExpense(@RequestParam("expense") MultipartFile expenses) throws Exception {
		
		if(expenses.isEmpty()) {
			return ResponseEntity.noContent().build();
		}
        
        ObjectMapper MAPPER = new ObjectMapper();
  	
		Result<List<Expense>> expense = MAPPER.readValue(expenses.getInputStream(), new TypeReference<Result<List<Expense>>>(){ });
				
		expenseService.importExpenses(expense.getData()); 
		
		return ResponseEntity.ok(Result.success());		
	}
	
	@ApiOperation(value="Upload expense and invoice")
	@PostMapping(value = "/expense/uploadall", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Result> uploadExpenseInvoice(@RequestParam("expense") MultipartFile expenses) throws Exception {
		
		log.debug("*****MultipartFile ContentType={}",expenses.getContentType());
		
		if(expenses.isEmpty() || !supportedUploadFileTypes.contains(expenses.getContentType())) {
			return ResponseEntity.ok(Result.failure().msg("Please choose a supported file type:" + supportedUploadFileTypes));
		}
		
		List<InvoiceImage> images = new ArrayList<InvoiceImage>();
		
		ZipInputStream zip = new ZipInputStream(expenses.getInputStream());		
		
		ZipEntry entry = zip.getNextEntry();
		
		Result result = new Result();
		while(entry != null) {
//			log.debug("entry.getName()={}", entry.getName());
			
			byte[] buffer = new byte[1024];
			ByteArrayOutputStream baos = new ByteArrayOutputStream();				
			int length = 0;
			while((length = zip.read(buffer)) != -1){
				baos.write(buffer, 0, length);
			}
			zip.closeEntry();
			
			if(entry.getName().endsWith(".json")) {				
				ObjectMapper MAPPER = new ObjectMapper();				
				Result<List<Expense>> expense = MAPPER.readValue(new ByteArrayInputStream(baos.toByteArray()), new TypeReference<Result<List<Expense>>>(){});				
				result = expenseService.importExpenses(expense.getData());				
			}else {				
				String entryName = entry.getName();
				String invoiceId = entryName.substring(entryName.lastIndexOf("/") + 1, entryName.indexOf("."));
				String mime = entryName.substring(entryName.indexOf(".") + 1);
//				log.debug("****invoiceId={}, mime={}",invoiceId, mime);
				InvoiceImage image = new InvoiceImage();
				image.setInvoiceId(invoiceId);
				image.setMime(mime);
				image.setImage(baos.toByteArray());
				images.add(image);
			}
			
			entry = zip.getNextEntry();
		}		

		log.debug("***Start to import invoice images into DRN");
		try {
			invoiceService.importInvoiceImages(images);
		}
		catch(Exception e) {
			log.error("***Failed to import invoice images");
		}
		
		return ResponseEntity.ok(result);		
	}	
	
//	 private static void doDecompressFile(File destFile, ZipInputStream zis) throws Exception {
//	        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
//	        int len;
//	        byte[] buff = new byte[DEFAULT_BUFF_SIZE];
//	        while ((len = zis.read(buff, 0 ,DEFAULT_BUFF_SIZE)) != -1) {
//	            bos.write(buff, 0, len);
//	        }
//	        bos.close();
//	    }
}
